#include "master.h"
#include "core.h"
#include "define.h"
#include "log.h"
#include <string.h>


static void _TaskDataFree(task_data_t *data) {
    if(data == nullptr) {
        return;
    }
    if (data->userName.base) {
        free(data->userName.base);
    }
    if (data->msg.base) {
        free(data->msg.base);
    }
    free(data);
}

static void _Run_Loop(void *arg)
{
    Master *master = (Master *)arg;

    master->RunLoop();

    return;
}


static void _RecvConnection(uv_stream_t *pServer, int status)
{
    LOG_DEBUG("_RecvConnection %d %p", status, pServer);
    LOG_DEBUG("_RecvConnection %p", pServer->data);
    if (status < 0 || pServer == NULL)
    {
        return;
    }
    
    Master *pMaster = (Master *)uv_handle_get_data((uv_handle_t *)pServer);
    if (pMaster == NULL) {
        uv_close((uv_handle_t *)pServer, NULL);
        return;
    }
    pMaster->OnRecvConnection(pServer);

    return;
}

static void _RecvWebConnection(uv_stream_t *pServer, int status)
{
    if (status < 0 || pServer == NULL)
    {
        return;
    }
    Master *pMaster = (Master *)uv_handle_get_data((uv_handle_t *)pServer);
    if (pMaster == NULL) {
        uv_close((uv_handle_t *)pServer, NULL);
        return;
    }
    pMaster->OnRecvWebConnection(pServer);

    return;
}

void _SendMsgToSpiderNode(uv_work_t* req) {
    LOG_DEBUG("_SendMsgToSpiderNode");
    auto pMaster = Core::GetInstance().GetMaster();
    if (pMaster) {
        task_data_t *data = (task_data_t *)uv_req_get_data((uv_req_t *)req);
        pMaster->DoSendMsgToSpiderNode(data);
    }
}

void _AfterSendMsgToSpiderNode(uv_work_t* req, int status) {
    task_data_t *data = (task_data_t *)uv_req_get_data((uv_req_t *)req);
    _TaskDataFree(data);
    free(req);
}

bool Master::Init(int spiderPort, int webPort, int interval, int commandTimeout, int idleTimeout)
{
    m_spiderPort = spiderPort;
    m_webPort = webPort;
    m_commandTimeout = commandTimeout;
    m_idleTimeout = idleTimeout;
    if (interval)
    {
        m_interval = interval;
    }
    else
    {
        m_interval = g_HeartbeatInterval;
    }
    LOG_INFO("Master Init SpiderPort:%d WebPort:%d", m_spiderPort, m_webPort);
    return true;
}

bool Master::Start()
{
    if (m_spiderPort == 0)
    {
        return true;
    }
    m_masterLoop = uv_loop_new();
    if (!m_masterLoop)
    {
        LOG_DEBUG("Master Loop create failed");
        exit(1);
    }
    uv_tcp_init(m_masterLoop, &m_spiderServer);
    sockaddr_in addr;
    uv_ip4_addr("0.0.0.0", m_spiderPort, &addr);
    uv_tcp_bind(&m_spiderServer, (const struct sockaddr*)&addr, 0);
    uv_handle_set_data((uv_handle_t *)&m_spiderServer, this);
    uv_listen((uv_stream_t *)&m_spiderServer, g_TcpListenSize, _RecvConnection);

    if (m_webPort)
    {
        uv_tcp_init(m_masterLoop, &m_webServer);
        uv_ip4_addr("0.0.0.0", m_webPort, &addr);
        uv_tcp_bind(&m_webServer, (const struct sockaddr*)&addr, 0);
        uv_handle_set_data((uv_handle_t *)&m_webServer, this);
        uv_listen((uv_stream_t *)&m_webServer, g_TcpListenSize, _RecvWebConnection);
    }
    if (uv_thread_create(&m_masterTid, _Run_Loop, this) != 0)
    {
        LOG_ERROR("master create thread failed");
    }
    return true;
}

void Master::Stop()
{
    for(auto &pair :m_spiderCache) {
        pair.second->Close(false);
    }
    uv_stop(m_masterLoop);
    if (m_masterTid > 0) {
        uv_thread_join(&m_masterTid);
    }
    m_spiderCache.clear();
}

void Master::RunLoop()
{
    LOG_DEBUG("Master::RunLoop");
    uv_run(m_masterLoop, UV_RUN_DEFAULT);
    return;
}

void Master::OnRecvConnection(uv_stream_t *pServer)
{
    LOG_DEBUG("OnRecvConnection");
    SpiderNode *pSpiderNode = new SpiderNode();
    if (pSpiderNode == NULL)
    {
        return;
    }
    if (!pSpiderNode->Init(this, pServer, m_interval))
    {
        LOG_ERROR("SpiderNode Init failed");
        return;
    }
    return;
}

void Master::OnRecvWebConnection(uv_stream_t *pServer)
{
    return;
}

bool Master::AddSpiderNodeCache(SpiderNode *pNode)
{
    if (m_spiderCache.count(pNode->m_uuid)) {
        LOG_ERROR("Add SpiderNode[%s] To Cache Failed, Because of repetition", pNode->m_uuid.c_str());
        return false;
    }
    m_spiderCache[pNode->m_uuid] = pNode;
    return true;
}

void Master::DelSpiderNodeCache(SpiderNode *pNode)
{
    if (m_spiderCache.count(pNode->m_uuid)) {
        m_spiderCache.erase(pNode->m_uuid);
    }
}

void Master::DoMsgToSpiderNode(std::string userName, char * msg, uint16_t msgLen)
{
    LOG_DEBUG("DoMsgToSpiderNode: %s", userName.c_str());
    task_data_t *data = (task_data_t *)calloc(1, sizeof(task_data_t));
    if (data == nullptr) {
        return ;
    }    
    data->msg.base = (char *)calloc(msgLen, sizeof(char));
    if (data->msg.base == nullptr) {
        _TaskDataFree(data);
        return ;
    }
    data->userName.base = (char *)calloc(userName.length(),sizeof(char));
    if (data->userName.base == nullptr) {
        _TaskDataFree(data);
        return;
    }
    memcpy(data->userName.base, userName.c_str(), userName.length());
    data->userName.len = userName.length();
    memcpy(data->msg.base, msg, msgLen);
    data->msg.len = msgLen;
    uv_work_t *req = (uv_work_t *)calloc(1, sizeof(uv_work_t));
    LOG_DEBUG("DoMsgToSpiderNode: data %p", data);
    uv_req_set_data((uv_req_t *)req, data);
    uv_queue_work(m_masterLoop, req, _SendMsgToSpiderNode, _AfterSendMsgToSpiderNode);
}

void Master::DoSendMsgToSpiderNode(task_data_t *data){
    //userName可定义规则转换为uuid
    LOG_DEBUG("DoSendMsgToSpiderNode");
    std::string uuid(data->userName.base, data->userName.len);
    if (m_spiderCache.count(uuid)) {
        m_spiderCache[uuid]->SendTask(data->msg.base, data->msg.len);
    }
}